package db;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

public class SQLPostValidator {
    
    /**
     * An enum class stores the status of validation result.
     * 
     * @author xzhang
     */
    public enum ValidateStatus {
        
        NOT_EXEC ("Not executed"), 
        IN_COMP_EXEC ("In-complete execution"), 
        COMP_EXEC ("Completely executed"), 
        VALID_FAIL ("Validation failed");
        
        private ValidateStatus(String desc) { this.desc = desc; }
        
        public String getDescription() { return this.desc; }
        
        private String desc;
    }
    
    public SQLPostValidator(Connection conn) {
        this.conn_ = conn;
    }
    
    /**
     * Get content of validation SQL file, execute queries in this file, to
     * check whether the SQL script corresponding to this validation SQL file
     * has been executed or not.
     * 
     * @param validSQLFile
     * @return validate status
     */
    public ValidateStatus validate(File validSQLFile) {
        
        ValidateStatus postValidationStatus;
        Statement stmt = null;
        
        try {
            String [] sqlStmts = SQLScriptParser.readScript(validSQLFile);
            stmt = conn_.createStatement();
            boolean status = true, result = false, executed = false;
            for(int i=0, n=sqlStmts.length; i < n; i++) {
                result = stmt.executeQuery(sqlStmts[i]).next();
                if (result == true) executed = true;
                else status = false;
            }
            if (true == status) {
                postValidationStatus = ValidateStatus.COMP_EXEC;
            }
            else if (false == status && executed == true) {
                postValidationStatus = ValidateStatus.IN_COMP_EXEC;
            }
            else {
                postValidationStatus = ValidateStatus.NOT_EXEC;
            }
            return postValidationStatus;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != stmt) stmt.close();
            } catch (SQLException e) {
                // do nothing
            }
        }
        postValidationStatus = ValidateStatus.VALID_FAIL;
        return postValidationStatus;
    }
    
    public ValidateStatus listValidate(File listFile, String validScriptPath) {

        String[] listOfSQLScripts = null;

        try {
            listOfSQLScripts = SQLListReader.readFromFile(listFile);
        } catch (IOException e) {
            e.printStackTrace();
            return ValidateStatus.VALID_FAIL;
        }
        ValidateStatus[] results = new ValidateStatus[listOfSQLScripts.length];
        for (int i = 0, n = listOfSQLScripts.length; i < n; i++) {
            String validScriptFile = validScriptPath
                    + System.getProperty("file.separator")
                    + getValidSQLScriptName(listOfSQLScripts[i]);
            results[i] = validate(new File(validScriptFile));
        }

        return getValidStatus(results);
    }

    private String getValidSQLScriptName(String sqlScriptName) {
        sqlScriptName = sqlScriptName.toLowerCase();
        if (!sqlScriptName.startsWith("create_") 
                && !sqlScriptName.startsWith("create-")
                && !sqlScriptName.endsWith(".sql")) {
            return null; // filter file name doesn't meet these reqs
        }
        return "valid" + sqlScriptName.substring("create".length());
    }

    private ValidateStatus getValidStatus(ValidateStatus[] results) {
        for (int i = 0, n = (results.length - 1); i < n; i++) {
            if (ValidateStatus.VALID_FAIL == results[i]) {
                return ValidateStatus.VALID_FAIL;
            }
            if (results[i] != results[i + 1]) {
                return ValidateStatus.IN_COMP_EXEC;
            }
        }
        return results[results.length - 1];
    }

    private Connection conn_;
}
